import logging
from django.utils import timezone
from typing import Literal
import tsl_backend.frontend_api.models.route as routes
import tsl_backend.frontend_api.models.order_routing as order_routing
import tsl_backend.frontend_api.models.workorder as workorders
import tsl_backend.frontend_api.serializers.serializers as frontend_serializers
import tsl_backend.frontend_api.utils.lib as frontend_lib
import tsl_backend.users.models as users

def create_order_routing(detail_obj):

    logging.info(f"Get standard routing of FGArticle {detail_obj.master} for order {detail_obj.order}")
    first_route_detail_obj=None
    standard_route_flows=detail_obj.master.routeflows_set.all().order_by("seq")
    if not standard_route_flows.exists():
        logging.info(f"Fail to get standard routing with FGArticle {detail_obj.master}. Filter with design/mould/gold_type")
        try:
            master_obj=routes.Master.objects.filter(design=detail_obj.design,
                                                    mould=detail_obj.mould,
                                                    gold_type=detail_obj.gold_type
                                                    ).first()
        except Exception as e:
            logging.warn(f"Fail to get master with alternative method: {e}")
        else:
            if master_obj:
                logging.info(f"Get master for {detail_obj} with alternative method: {master_obj}")
                standard_route_flows=master_obj.routeflows_set.all()
            else:
                logging.warn(f"Fail to get master for {detail_obj} with alternative method")
                
    else:
        logging.info(f"Standard routing for order {detail_obj.order} is available: {standard_route_flows}")
    #     standard_route_flows=None

    if standard_route_flows.exists():
        # logging.info(f"Create orderRouting for order {detail_obj.order}")
        # order_route_obj, _create=order_routing.OrderRouting.objects.get_or_create(workorder=detail_obj)
        # if not _create:
        #     logging.info(f"orderRouting for order {detail_obj.order} already exists")
        #     return order_route_obj

        route_detail_objs = order_routing.RouteDetail.objects.filter(order_route=detail_obj.orderrouting)
        if not route_detail_objs.exists():
            logging.info(f"No route detail. Create Route detail for all the flow according to standard routing.")
            for standard_route_flow in standard_route_flows:
                logging.info(f"Add standard route {standard_route_flow.flow} seq {standard_route_flow.seq} to order {detail_obj.order}")
                route_detail_obj=order_routing.RouteDetail.objects.create(flow=standard_route_flow.flow,
                                                                        quantity=standard_route_flow.quantity,
                                                                        difficulty=standard_route_flow.difficulty,
                                                                        primary_stone_setting=standard_route_flow.primary_stone_mount_setting,
                                                                        secondary_stone_setting=standard_route_flow.secondary_stone_mount_setting,
                                                                        consumption_percentage=standard_route_flow.consumption_percentage,
                                                                        worker_fee=standard_route_flow.worker_fee,
                                                                        seq=standard_route_flow.seq,
                                                                        order_route=detail_obj.orderrouting
                                                                        )
                logging.info(f"{route_detail_obj} is created for order {detail_obj.order}")
                
                if standard_route_flow.seq==1:
                    first_route_detail_obj=route_detail_obj

            # create Record for first flow
            if first_route_detail_obj:
                logging.info(f"Standard route seq is 1, create record for first flow: {first_route_detail_obj}")
                order_flow_record_obj=create_order_flow_record(first_route_detail_obj)
                logging.info(f"Record {order_flow_record_obj} is created for order {detail_obj}")

    else:
        logging.info("Standard route does not exists. Fail to create order routing")


# get the last active flow of the order flows
def get_last_order_flow(detail_obj):
    # it will create routing of the order and Record of first flow
    logging.info(f"Get last order flow for {detail_obj}")
    order_routing_obj=None  
    last_order_flows_obj=None
    try:
        order_routing_obj=order_routing.OrderRouting.objects.only("id").get(workorder=detail_obj)
    except order_routing.OrderRouting.DoesNotExist:
        logging.error("No order routing exists.")
        
        # Do not create new routing when get order flow
        # order_routing_obj=create_order_routing(detail_obj)
        # print(order_routing_obj)
    except Exception as e:
        logging.info("Exception of get_last_order_flow: {e}")
    else:
        # print(order_routing_obj)
        last_order_flows_obj=order_routing_obj.routedetail_set.only("id").filter(status__range=(1,2)).order_by('seq').first()
    return last_order_flows_obj


def get_last_order_flow_record(detail_obj):
    logging.debug(f"Filter last order flow record for {detail_obj}")
    # try:
    last_order_flow_obj=get_last_order_flow(detail_obj)
    last_order_flow_record_obj=order_routing.Record.objects.filter(route_detail=last_order_flow_obj).last()
    # except order_routing.Record.DoesNotExist:
    #     last_order_flow_record_obj=order_routing.Record.objects.none()
    logging.info(f"Last record obj for order {detail_obj}: {last_order_flow_record_obj}")
    return last_order_flow_record_obj

def get_latest_order_flow_record_by_role_bak(detail_obj, user_account_obj):
    logging.info(f"TO check repeat flow occur. Get the last round the flow record start")
    # try:
    # route_detail_obj = detail_obj.orderrouting
    last_order_flow_obj=get_last_order_flow(detail_obj)
    logging.info(f"{last_order_flow_obj=}")

    # last_order_flow_record_obj=order_routing.Record.objects.filter(route_detail=last_order_flow_obj).last()
    last_order_flow_record_objs=order_routing.Record.objects.filter(route_detail=last_order_flow_obj).order_by("-pk")
    logging.info(f"Filter Record for route_detail={last_order_flow_obj}: {last_order_flow_record_objs}")
    # except order_routing.Record.DoesNotExist:
    #     last_order_flow_record_obj=order_routing.Record.objects.none()

    # count if rework exists
    if last_order_flow_record_objs.count()>1:
        # rework for this order
        # check if last order start
        last_order_flow_record_obj=last_order_flow_record_objs.last()

        if last_order_flow_record_obj.worker.account:
            # start already, this is the last record
            pass
        else:
            # get the previous record
            last_order_flow_record_obj=last_order_flow_record_objs[1]
    else:
        last_order_flow_record_obj=last_order_flow_record_objs.last()

    logging.info(f"last_order_flow_record_obj for order {detail_obj} is {last_order_flow_record_obj}")
    
    return last_order_flow_record_obj

def get_latest_order_flow_record_by_role(detail_obj, user_account_obj):
    logging.info(f"TO check repeat flow occur. Get the last round the flow record start")
    # try:
    # route_detail_obj = detail_obj.orderrouting
    last_order_flow_obj=get_last_order_flow(detail_obj)
    logging.info(f"{last_order_flow_obj=}")

    # last_order_flow_record_obj=order_routing.Record.objects.filter(route_detail=last_order_flow_obj).last()
    last_order_flow_record_objs=order_routing.Record.objects.filter(route_detail=last_order_flow_obj).order_by("-pk")
    logging.info(f"Filter Record for route_detail={last_order_flow_obj}: {last_order_flow_record_objs}")
    # except order_routing.Record.DoesNotExist:
    #     last_order_flow_record_obj=order_routing.Record.objects.none()

    # count if rework exists
    if last_order_flow_record_objs.count()>1:
        # rework for this order
        # check if last order start
        last_order_flow_record_obj=last_order_flow_record_objs.last()

        if last_order_flow_record_obj.worker.account:
            # start already, this is the last record
            pass
        else:
            # get the previous record
            last_order_flow_record_obj=last_order_flow_record_objs[1]
    else:
        last_order_flow_record_obj=last_order_flow_record_objs.last()

    logging.info(f"last_order_flow_record_obj for order {detail_obj} is {last_order_flow_record_obj}")
    
    return last_order_flow_record_obj


def check_or_create_order_routing(detail_obj):
    # it will create routing of the order and Record of first flow
    # create OrderRouting
    order_route_obj, created = order_routing.OrderRouting.objects.get_or_create(workorder=detail_obj)
    logging.info(f"Get or Create new OrderRouting for order {detail_obj.order}? {created}")

    # create RouteDetail
    # route_detail_exists = order_routing.RouteDetail.objects.filter(order_route=order_route_obj).exists()
    # if route_detail_exists:
    #     logging.info(f"Order routing exists for order {detail_obj}")
    # else:
    # logging.info(f"Order routing does not exist for order {detail_obj}. Create order routing.")

    # create routing and Record of first flow
    create_order_routing(detail_obj)

    logging.info(f"Order routing and Record of flow seq 1 are created for order {detail_obj}")

def check_route_detail_flow_record(record_obj: order_routing.Record, flow_obj: users.Flow):
    """检查当前的flow与record是否一致,并修复"""
    scan_and_record=flow_obj.scan_and_record
    qc_check=flow_obj.qc_check  
    leader_check=flow_obj.leader_check
    stone_check=flow_obj.stone_exam

    if scan_and_record and (not record_obj.worker):
        worker_obj=order_routing.WorkerRecord.objects.create()
        record_obj.worker=worker_obj
    
    if qc_check and (not record_obj.qc_check):
        qc_check_obj=order_routing.CheckRecord.objects.create(check_type=1)
        record_obj.qc_check=qc_check_obj

    if leader_check and (not record_obj.leader_check):
        leader_check_obj=order_routing.CheckRecord.objects.create(check_type=2)
        record_obj.leader_check=leader_check_obj

    if stone_check and (not record_obj.stone_check):
        stone_check_obj=order_routing.CheckRecord.objects.create(check_type=3)
        record_obj.stone_check=stone_check_obj

    record_obj.save()


def create_order_flow_record(route_detail_obj):
    logging.info(f"Create new record for {route_detail_obj}")
    if route_detail_obj:
        scan_and_record=route_detail_obj.flow.scan_and_record
        qc_check=route_detail_obj.flow.qc_check  
        leader_check=route_detail_obj.flow.leader_check
        stone_check=route_detail_obj.flow.stone_exam

        if scan_and_record:
            worker_obj=order_routing.WorkerRecord.objects.create()
        else:
            worker_obj=None
        
        if qc_check:
            qc_check_obj=order_routing.CheckRecord.objects.create(check_type=1)
        else:
            qc_check_obj=None

        if leader_check:
            leader_check_obj=order_routing.CheckRecord.objects.create(check_type=2)
        else:
            leader_check_obj=None

        if stone_check:
            stone_check_obj=order_routing.CheckRecord.objects.create(check_type=3)
        else:
            stone_check_obj=None
        
        order_flow_record_obj=order_routing.Record.objects.create(route_detail=route_detail_obj, worker=worker_obj, qc_check=qc_check_obj, leader_check=leader_check_obj, stone_check=stone_check_obj)
        logging.info(f"Created new record {order_flow_record_obj} for {route_detail_obj}")
        if worker_obj == qc_check_obj == leader_check_obj == stone_check_obj == None:
            
            # Check to see can skip dispatcher
            can_skip_dispatcher = check_flow_dispatcher_config(route_detail_obj.flow)
            if can_skip_dispatcher:
                logging.info(f"No record need for this flow. Flow complete. Create new record for next flow")
                route_detail_obj=update_route_status(route_detail_obj, 3)

                # createfor next record
                # logging.info(f"Create record for next flow. Current is {route_detail_obj}")
                # order_flow_record_obj=create_record_for_next_flow(route_detail_obj)
                # logging.info(f"New record is created: {order_flow_record_obj}")
                # if new_record_obj:
                #     return order_flow_record_obj
            else:
                logging.info(f"Need dispatcher")
                if route_detail_obj.flow.chinese_name != "PF":
                    route_detail_obj=update_route_status(route_detail_obj, 2)

        return order_flow_record_obj
    else:
        logging.info(f"No flow is found for {route_detail_obj}")
        return None

def check_worker_complete(worker_record_obj):
    if worker_record_obj.workeractionrecord_set.filter(action=3).exists():
        return True
    else:
        return False


def check_worker_status(worker_record_obj):
    if worker_record_obj.workeractionrecord_set.all().exists():
        logging.info(f"Worker starts job")
        return True
    else:
        logging.info(f"Worker does not start job")
        return False

def check_qc_complete(qc_check_record_obj):
    if qc_check_record_obj.check_at:
        return True
    else:
        return False
    
def check_qc_result_fail(qc_check_record_obj):
    if qc_check_record_obj.failed:
        return True
    else:
        return False


def check_qc_result(qc_check_record_obj):
    if qc_check_record_obj.failed:
        failed=True
    else:
        failed=False
    return failed
    

def check_last_step_and_perm(order_flow_record_obj, account_obj):
    # all last record should be the lastest record. New record will be created when QC failed
    error_message = None
    order =order_flow_record_obj.route_detail.order_route
    if order_flow_record_obj.route_detail.flow==account_obj.department.flow:
        logging.info(f"user account {account_obj.role.name} is in the same flow with the order flow {order_flow_record_obj.worker}")
        
        # check last step of order
        if account_obj.role.name=="WORKER":
            if order_flow_record_obj.worker:
                # order_routing.WorkerActionRecord.objects.filter(workorder=order_flow_record_obj.worker)
                worker_action_record_objs=order_flow_record_obj.worker.workeractionrecord_set.all()
                # print(worker_action_record_objs)

                if worker_action_record_objs.exists():
                    if worker_action_record_objs.last().action==3:
                        logging.info(f"Worker process complete for order {worker_action_record_objs.last()}")
                        error_message = "工序已完成"
                        return False ,error_message

                    else:
                        logging.info(f"Worker process is current step for order {worker_action_record_objs}")
                        have_perm=check_user_role_is_same_as_flow("WORKER", account_obj)
                        if have_perm is False:
                            error_message = "角色不在此工作程序"
                        return have_perm ,error_message
                else:
                    logging.info(f"Work process not start yet. Worker process is current step for order {worker_action_record_objs}")
                    have_perm=True
                    return have_perm , error_message
                
            else:
                error_message = '角色没有访问权限'
                return False, error_message

        elif account_obj.role.name=="QC":
            logging.info(f"Check QC complete")
            logging.info(f"{order_flow_record_obj=}")
            logging.info(f"{order_flow_record_obj.qc_check=}")
            if order_flow_record_obj.qc_check:
                logging.info(f"Check worker complete: {order_flow_record_obj.worker}")
                worker_is_start=check_worker_status(order_flow_record_obj.worker) if order_flow_record_obj.worker else True

                if worker_is_start:
                    qc_is_complete=check_qc_complete(order_flow_record_obj.qc_check)
                    if qc_is_complete:
                        logging.info(f"QC complete for order {order}.")
                        error_message = "工序已完成"
                        return False ,error_message
                    else:
                        # Check if worker start the job, yes, auto complete, else, False
                        logging.info(f"QC is current step for order {order}.")
                        have_perm=check_user_role_is_same_as_flow("QC", account_obj)
                        if have_perm is False:
                            error_message = "角色不在此工作程序"
                        return have_perm, error_message

                else:
                    qc_is_complete=False 
                    return False, "Qc审核"
                    # different from leader as QC can start the flow even if worker is incomplete. Will auto complete the worker flow
            else:
                error_message = '角色没有访问权限'
                return False, error_message
                
        elif account_obj.role.name=="Teamleader":
            logging.info(f"Check Teamleader complete")
            logging.info(f"{order_flow_record_obj=}")
            logging.info(f"{order_flow_record_obj.leader_check=}")
            if order_flow_record_obj.leader_check:
                worker_is_complete=check_worker_complete(order_flow_record_obj.worker) if order_flow_record_obj.worker else True
                qc_is_complete=check_qc_complete(order_flow_record_obj.qc_check) if order_flow_record_obj.qc_check else True

                if worker_is_complete and qc_is_complete:
                    leader_is_complete=check_qc_complete(order_flow_record_obj.leader_check)
                  
                else:
                    logging.info(f"Leader cannot start as not last previous step is not complete")
                    leader_is_complete=False 
                    error_message = '上一步骤未完成'
                    return False, error_message

                if leader_is_complete:
                    logging.info(f"Leader complete for order {order}.")
                    error_message = "工序已完成"
                    return False ,error_message
                else:
                    logging.info(f"Leader is current step for order {order}")
                    have_perm=check_user_role_is_same_as_flow("Teamleader", account_obj)
                    if have_perm is False:
                            error_message = "角色不在此工作程序"
                    return have_perm, error_message

            else:
                logging.info(f"No leader check record")

                error_message = '角色没有访问权限'
                return False, error_message
                
        elif account_obj.role.name=="StoneQC":
            if order_flow_record_obj.stone_check:
                worker_is_complete=check_worker_complete(order_flow_record_obj.worker) if order_flow_record_obj.worker else True
                qc_is_complete=check_qc_complete(order_flow_record_obj.qc_check) if order_flow_record_obj.qc_check else True
                leader_is_complete=check_qc_complete(order_flow_record_obj.leader_check) if order_flow_record_obj.leader_check else True

                logging.info(f"worker complete job: {worker_is_complete}, QC complete job:{qc_is_complete}, Leader complete job:{leader_is_complete}")

                if worker_is_complete and qc_is_complete and leader_is_complete:
                    logging.info(f"Previous step is complete, check if StoneQC complete")
                    stone_check_is_complete=check_qc_complete(order_flow_record_obj.stone_check)
                else:
                    logging.info(f"StoneQC cannot start as not last previous step is not complete")
                    stone_check_is_complete=False 
                    error_message = "上一步骤未完成"
                    return False, error_message


                if stone_check_is_complete:
                    logging.info(f"Stone process complete for order {order}")
                    error_message = "工序已完成"
                    return False ,error_message
                else:
                    logging.info(f"Stone process is current step for order {order}")
                    have_perm=check_user_role_is_same_as_flow("StoneQC", account_obj)
                    if have_perm is False:
                        error_message = "角色不在此工作程序"
                    return have_perm, error_message
            else:
                error_message = '角色没有访问权限'
                return False, error_message
        else:
            logging.info(f"Other roles {account_obj.role.name}")
            return True, error_message

    else:
        logging.info(f"user account {account_obj} is not in the same flow with the order flow {order_flow_record_obj}")
        error_message = '不在相同工单节点'

        return False, error_message


def check_user_role_is_same_as_flow(order_flow, account_obj):
    # complare user role and flow
    logging.info(f"user role: {account_obj.role.name}, order_flow:{order_flow}")
    if account_obj.role.name==order_flow:
        return True
    else:
        return False
 
 
def check_user_account_is_same_as_flow(account_obj, order_flow_obj):
    if order_flow_obj.flow==account_obj.department.flow:
        logging.info(f"User {account_obj} is in the same flow {order_flow_obj.flow} of order")
        return True
    else:
        logging.info(f"User {account_obj} is not in the same flow {order_flow_obj.flow} of order")
        return False


def check_user_can_change_status(detail_obj, last_order_flow_record_obj, account_obj):
    logging.info(f"Check if user {account_obj} has perm to change order {detail_obj} status for {last_order_flow_record_obj}")
    # check user and holder is the same
    have_perm=False
    error_message = None
    # check flow step
    if last_order_flow_record_obj:
        have_perm , error_message = check_last_step_and_perm(last_order_flow_record_obj, account_obj)
    else:
        # logging.info("No flow record exist. Create the flow record for first flow")
        logging.warn("No flow record exist. Check the reason for missing flow record")
        # get the first flow 
        # first_order_flow_obj=order_routing.RouteDetail.objects.filter(order_route__workorder=detail_obj).order_by('seq').first()
        # last_order_flow_record_obj=create_order_flow_record(first_order_flow_obj)
        # if last_order_flow_record_obj:
        #     have_perm=check_user_can_change_status(detail_obj, last_order_flow_record_obj, account_obj)
    logging.info(f"User {account_obj} is the same flow with the order: {have_perm}")
    if have_perm:
        # check if user is the receiver of the record
        if account_obj.role.name=="WORKER":
            if last_order_flow_record_obj.worker.account:
                if last_order_flow_record_obj.worker.account!=account_obj:
                    logging.info(f"User {account_obj} is not the user to start the worker job {last_order_flow_record_obj.worker.account}")
                    have_perm=False
        elif account_obj.role.name=="QC":
            if last_order_flow_record_obj.qc_check.account:
                if last_order_flow_record_obj.qc_check.account!=account_obj:
                    logging.info(f"User {account_obj} is not the user to start the QC job {last_order_flow_record_obj.qc_check.account}")
                    have_perm=False
        elif account_obj.role.name=="Teamleader":
            if last_order_flow_record_obj.leader_check.account:
                if last_order_flow_record_obj.leader_check.account!=account_obj:
                    logging.info(f"User {account_obj} is not the user to start the leader job {last_order_flow_record_obj.leader_check.account}")
                    have_perm=False
        elif account_obj.role.name=="StoneQC":
            if last_order_flow_record_obj.stone_check.account:
                if last_order_flow_record_obj.stone_check.account!=account_obj:
                    logging.info(f"User {account_obj} is not the user to start the stone job {last_order_flow_record_obj.stone_check.account}")
                    have_perm=False
        else:
            logging.info(f"No correct role name {account_obj.role.name} is found for user {account_obj}")
            error_message = "角色名称错误, 没有访问权限"
            have_perm=False
    # else:
    #     error_message = "工艺节点不同, 没有访问权限"

    logging.info(f"User {account_obj} has perm to change status: {have_perm}, error message: {error_message}")
    return have_perm, error_message


def check_user_hold_status(order_route_obj, account_obj):
    # check flow step
    on_hold=False
    if account_obj==order_route_obj.holder:
        on_hold=True
    logging.info(f"Order {order_route_obj.workorder} is hold by {account_obj}: {on_hold}")
    return on_hold


def check_current_flow_end(route_detail_obj, current_step):
    last_step=False
    if route_detail_obj.flow.stone_exam:
        if current_step=="stone_exam":
            last_step=True
    elif route_detail_obj.flow.leader_check:
        if current_step=="leader_check":
            last_step=True
    elif route_detail_obj.flow.qc_check:
        if current_step=="qc_check":
            last_step=True
    elif route_detail_obj.flow.scan_and_record:
        if current_step=="scan_and_record":
            last_step=True
    logging.info(f"{current_step} is the last step for flow {route_detail_obj.flow}? {last_step}")
    return last_step


def update_route_status(route_detail_obj, status):
    logging.info(f"Update route {route_detail_obj} status to {status}")
    route_detail_obj.status=status
    route_detail_obj.save(update_fields={"status"})

    # create record for next flow
    # TODO: scenerio, if update the status to 3 and fail to create new record for next flow. It will be stuck and cannot go to next step.
    if status==3:
        create_record_for_next_flow(route_detail_obj)
    
    return route_detail_obj

def update_worker_count(worker_obj):
    worker_obj.work_count+=1
    worker_obj.save(update_fields={"work_count"})
    logging.info(f"Update worker record {worker_obj} work_count to {worker_obj.work_count}")
    return worker_obj


def check_worker_record_editable(worker_obj):
    editable=False
    last_workeractionrecord_obj=None
    # print(worker_obj)
    workeractionrecord_obj=worker_obj.workeractionrecord_set.all()
    if workeractionrecord_obj.exists():
        last_workeractionrecord_obj=workeractionrecord_obj.last()
        logging.info(f"worker action record {last_workeractionrecord_obj}")

        if last_workeractionrecord_obj.action==3:
            editable=False
        else:
            editable=True
    else:
        editable=True

    logging.info(f"worker record {worker_obj} editable: {editable}")
    return editable, last_workeractionrecord_obj

def check_qc_record_editable(check_record_obj):
    editable=False
    if check_record_obj.check_at:
        editable=False
    else:
        editable=True
    logging.info(f"Check record {check_record_obj} editable: {editable}")
    return editable

def update_holder_account(holder, order_route_obj):
    order_route_obj.holder=holder
    order_route_obj.holder_record_time=timezone.now()
    order_route_obj.save(update_fields={"holder", "holder_record_time"})
    return order_route_obj

def get_next_step_of_flow(route_detail_obj, curent_role_record_obj):
    next_role=None
    logging.info(f"Current role is {curent_role_record_obj}")
    if isinstance(curent_role_record_obj, order_routing.WorkerRecord):
        if route_detail_obj.flow.qc_check:
            next_role="qc_check"
        elif route_detail_obj.flow.leader_check:
            next_role="leader_check"
        elif route_detail_obj.flow.stone_exam:
            next_role="stone_exam"
        else:
            next_role=None
    elif isinstance(curent_role_record_obj, order_routing.CheckRecord):
        if curent_role_record_obj.check_type==1:
            if route_detail_obj.flow.leader_check:
                next_role="leader_check"
            elif route_detail_obj.flow.stone_exam:
                next_role="stone_exam"
            else:
                next_role=None
        elif curent_role_record_obj.check_type==2:
            if route_detail_obj.flow.stone_exam:
                next_role="stone_exam"
            else:
                next_role=None
        elif curent_role_record_obj.check_type==3:
            next_role=None

    return next_role


def get_next_role_record_of_flow(route_detail_obj, role_record_obj):
    if not role_record_obj:
        if route_detail_obj.flow.scan_and_record:
            next_role="worker"
        elif route_detail_obj.flow.qc_check:
            next_role="qc_check"
        elif route_detail_obj.flow.leader_check:
            next_role="leader_check"
        elif route_detail_obj.flow.stone_exam:
            next_role="stone_exam"
        else:
            next_role=None

    elif isinstance(role_record_obj, order_routing.WorkerRecord):
        if route_detail_obj.flow.qc_check:
            next_role="qc_check"
        elif route_detail_obj.flow.leader_check:
            next_role="leader_check"
        elif route_detail_obj.flow.stone_exam:
            next_role="stone_exam"
        else:
            next_role=None
    elif isinstance(role_record_obj, order_routing.CheckRecord):
        if role_record_obj.check_type==1:
            if route_detail_obj.flow.leader_check:
                next_role="leader_check"
            elif route_detail_obj.flow.stone_exam:
                next_role="stone_exam"
            else:
                next_role=None
        elif role_record_obj.check_type==2:
            if route_detail_obj.flow.stone_exam:
                next_role="stone_exam"
            else:
                next_role=None
        elif role_record_obj.check_type==3:
            next_role=None
        else:
            next_role=None
    else:
        next_role=None

    return next_role


def check_role_record_start(role_record_obj):
    started=False
    if isinstance(role_record_obj, order_routing.WorkerRecord):
        if role_record_obj.account:
            started=True
    elif isinstance(role_record_obj, order_routing.CheckRecord):
        if role_record_obj.received_at:
            started=True

    return started


def get_role_of_record(record_obj, role):
    if role=="worker":
        return record_obj.worker
    elif role=="qc_check":
        return record_obj.worker
    elif role=="leader_check":
        return record_obj.worker
    elif role=="stone_exam":
        return record_obj.stone_check
    else:
        return None


def get_next_flow_record(current_record_obj):
    route_detail_obj=current_record_obj.route_detail
    current_seq=route_detail_obj.seq
    next_seq=current_seq+1
    next_route_detail_objs=order_routing.RouteDetail.objects.filter(seq=next_seq, order_route=route_detail_obj.order_route)
    if not next_route_detail_objs.exists():
        next_route_detail_obj=next_route_detail_objs.last()
        logging.warn("No next flow exists")
    else:
        next_route_detail_obj=next_route_detail_objs.get()

    return next_route_detail_obj

def check_next_step_start_for_qc(check_record_obj):
    next_step_start=False
    if check_record_obj.check_type==1:
        record_obj=check_record_obj.qc_check.get()
        current_role="qc_check"
    elif check_record_obj.check_type==2:
        record_obj=check_record_obj.leader_check.get()
        current_role="leader_check"
    elif check_record_obj.check_type==3:
        record_obj=check_record_obj.stone_check.get()
        current_role="stone_exam"
    else:
        route_detail_obj=None
        logging.warn(f"Check_type is out out range {check_record_obj.check_type}")
        return next_step_start

    # print("check_record_obj: ", check_record_obj)
    # print("record_obj: ", record_obj)
    route_detail_obj=record_obj.route_detail
    last_step=check_current_flow_end(route_detail_obj, current_role)
    if last_step:
        # check next first step of next flow
        next_route_detail_obj=get_next_flow_record(record_obj)
        if next_route_detail_obj:
            record_obj=next_route_detail_obj.record_set.last()
            role=get_next_role_record_of_flow(route_detail_obj, None)
            if record_obj:
                role_record_obj=get_role_of_record(record_obj, role)
                next_step_start=check_role_record_start(role_record_obj)
        

    else:
        # check next step
        next_role=get_next_step_of_flow(route_detail_obj, record_obj)
        next_role_record_obj=get_role_of_record(record_obj, next_role)
        next_step_start=check_role_record_start(next_role_record_obj)

    logging.info(f"Next step started: {next_step_start}")
    return next_step_start

def check_qc_record_can_reset(check_record_obj):
    allow_reset=False
    if check_qc_record_editable(check_record_obj):
        logging.info(f"Set allow to reset to false as the qc result is editable for user. No need to reset.")
        allow_reset=False
    else:
        # check next step start
        next_step_start=check_next_step_start_for_qc(check_record_obj)
        logging.info(f"The QC result is submitted. Check next step started: {next_step_start}")
        if not next_step_start:
            allow_reset=True

    logging.info(f"Check record {check_record_obj} allow for reset: {allow_reset}")
    return allow_reset

def create_record_for_next_flow(route_detail_obj):
    logging.info(f"Prepare to create record for next flow.")
    new_seq=route_detail_obj.seq+1
    logging.info(f"Current route detail is {route_detail_obj} at seq {route_detail_obj.seq}.")

    logging.info(f"Filter for the route detail with seq is {new_seq}")
    route_detail_objs=order_routing.RouteDetail.objects.filter(order_route=route_detail_obj.order_route, seq=new_seq)
    
    if route_detail_objs.exists():
        try:
            next_route_detail_obj=route_detail_objs.get()
            logging.info(f"Preapre to create new record for {next_route_detail_obj}")
        except Exception as e:
            logging.info(f"Fail to get next route detail: {e}")
        else:
            new_record_obj=create_order_flow_record(next_route_detail_obj)
            logging.info(f"New record {new_record_obj} is created for {next_route_detail_obj}")
            return new_record_obj
    else:
        logging.info(f"No seq {new_seq} routing exists")

    return None

def check_flow_dispatcher_config(flow_obj):
    if flow_obj.dispatcher_check:
        can_skip_dispatcher=False
    else:
        can_skip_dispatcher=True
    logging.info(f"Can skip dispatcher record from FGR? {can_skip_dispatcher}")

    return can_skip_dispatcher

def update_route_detail_status(user_record_obj):
    # check if the user complete the work and is last step in flow, if yes, update status of route detail
    user_complete=False
    logging.info(f"{user_record_obj=}")
    if isinstance(user_record_obj, order_routing.WorkerRecord):
        logging.info(f"{user_record_obj=}")
        logging.info(f"{user_record_obj.record_set.all()=}")
        record_obj=user_record_obj.record_set.last()
        current_step="scan_and_record"
        # check complete status
        # user_complete=record_obj.worker.workeractionrecord_set.filter(action=3).exists()
        
        # TODO need to further check how to pass the data from serializer
        # user_complete=check_worker_complete(record_obj.worker)
        user_complete=True

    elif isinstance(user_record_obj, order_routing.CheckRecord):
        if user_record_obj.check_type==1:
            record_obj=user_record_obj.qc_check.last()
            current_step="qc_check"
            user_complete=True if record_obj.qc_check.check_at else False

        elif user_record_obj.check_type==2:
            record_obj=user_record_obj.leader_check.last()
            current_step="leader_check"
            user_complete=True if record_obj.leader_check.check_at else False
            
        elif user_record_obj.check_type==3:
            record_obj=user_record_obj.stone_check.last()
            current_step="stone_exam"
            user_complete=True if record_obj.stone_check.check_at else False
        else:
            logging.warn(f"No check type {record_obj}")
    else:
        logging.info("No user record found")

    last_step=check_current_flow_end(record_obj.route_detail, current_step)

    can_skip_dispatcher = check_flow_dispatcher_config(record_obj.route_detail.flow)

    if can_skip_dispatcher and last_step and user_complete:
        # record_obj.route_detail.status=3
        # record_obj.route_detail.save(update_fields={"status"})
        update_route_status(record_obj.route_detail, 3)

        # logging.info(f"Currenct flow {record_obj.route_detail} complete. Check and create record for next flow.")
        # create_record_for_next_flow(record_obj.route_detail)

def check_allow_qc_reset(last_record_obj_by_role, account_obj, last_record_obj):
    # TODO check worker start, if yes, not allow to reset, else, allow to reset
    logging.info(f"Check allow QC to reset result")
    logging.info(f"{last_record_obj_by_role=}")
    logging.info(f"{last_record_obj=}")
    allow_reset=False
    if last_record_obj_by_role:
        if last_record_obj_by_role!=last_record_obj:
            if account_obj.role.name=="QC":
                logging.info(f"Fail flow handling, check worker start for last_record_obj")
                worker_start = check_worker_status(last_record_obj.worker)
                if worker_start:
                    logging.info(f"Worker started the flow. Cannot reset the result")
                    allow_reset=False
                else:
                    logging.info(f"Worker did not start the flow. Can reset the result")
                    allow_reset=True
        else:
            if account_obj.role.name=="QC":
                check_record_obj=last_record_obj_by_role.qc_check
            elif account_obj.role.name=="Teamleader":
                check_record_obj=last_record_obj_by_role.leader_check
            elif account_obj.role.name=="StoneQC":
                check_record_obj=last_record_obj_by_role.stone_check
            else:
                check_record_obj=None
            if check_record_obj:
                next_step_start=check_next_step_start_for_qc(check_record_obj)
                if not next_step_start:
                    allow_reset=True
                else:
                    logging.info(f"{last_record_obj_by_role} next step already staert. Not allow to reset result")
    else:
        logging.info(f"No order routing")
    return allow_reset


def complete_worker_job(record_obj):
    workactionrecord_obj=None
    worker_complete=check_worker_complete(record_obj.worker)
    if not worker_complete:
        logging.info(f"Update worker completion record {record_obj}")
        
        action_data={"account_pk":record_obj.worker.account.pk, "worker_record": record_obj.worker.pk, "action":3} 
        worker_action_serializer=frontend_serializers.WorkerActionSerializer(data=action_data)
        if worker_action_serializer.is_valid():
            workactionrecord_obj = worker_action_serializer.save()
        else:
            logging.error(f"Fail to auto complete the worker job: {worker_action_serializer.errors} ")
    else:
        logging.info(f"Worker record is already complete. No need to auto completion for record {record_obj}")
            
    return workactionrecord_obj

def delete_order_routing_after_seqx(last_seq, order_route_obj):
    route_detail_objs=order_routing.RouteDetail.objects.filter(seq__gt=last_seq, order_route=order_route_obj)
    if route_detail_objs.exists():
        seq_flow_id_list = route_detail_objs.values_list("id", flat=True)
        # 查询出被引用的(这些删除会报错)
        record_id_list = set(order_routing.Record.objects.filter(route_detail_id__in=seq_flow_id_list).values_list("route_detail_id", flat=True))
        actual_weight_id_list = set(order_routing.ActualWeight.objects.filter(route_detail_id__in=seq_flow_id_list).values_list("route_detail_id", flat=True))
        # 被应用的flow
        use_seq_flow_id_list = record_id_list.union(actual_weight_id_list)

        # 删除没有被引用的
        delete_flow_id = set(seq_flow_id_list) - use_seq_flow_id_list
        logging.info(f"Delete Route detail objs with seq greater than {last_seq}: {route_detail_objs}")
        if delete_flow_id:
            route_detail_objs.filter(id__in=delete_flow_id).delete()

def check_order_discard(detail_obj):
    if detail_obj.state==2:
        logging.info(f"order {detail_obj} is discarded.")
        return True
    else:
        return False


def create_record_for_next_flow_for_dispatcher(route_detail_obj):
    new_seq=route_detail_obj.seq+1

    route_detail_objs=order_routing.RouteDetail.objects.filter(order_route=route_detail_obj.order_route, seq=new_seq)

    if route_detail_objs.exists():
        try:
            next_route_detail_obj=route_detail_objs.get()
        except Exception as e:
            logging.info(f"Fail to get next route detail: {e}")
        else:
            # check if any record for next flow
            record_objs = order_routing.Record.objects.filter(route_detail=next_route_detail_obj)
            if not record_objs.exists():
                new_record_obj=create_order_flow_record(next_route_detail_obj)
                logging.info(f"New record {new_record_obj} is created for {next_route_detail_obj}")
                return new_record_obj

            else:
                logging.info(f"Record already created for next flow. Do not create new record: {record_objs}")

    else:
        logging.info(f"No seq {new_seq} routing exists")

    return None

def update_order_state(detail_obj, state):
    logging.info(f"Update order {detail_obj} state to {state}")
    detail_obj.state=state
    detail_obj.save(update_fields=["state"])

def update_order_complete_date(order_routing_obj,PFDate):
    logging.info(f"Update order complete date {order_routing_obj} PFDate to {PFDate}")
    order_routing_obj.order_complete_date=PFDate
    order_routing_obj.save(update_fields=["order_complete_date"])

def get_master_obj(fg_article, design, mould, gold_type):
    logging.info(f"Filter master with FG article {fg_article}")
    master_objs = routes.Master.objects.filter(fg_article=fg_article)
    if master_objs.exists():
        master_obj=master_objs.first()
        logging.info(f"Get master {master_obj} with fg article {fg_article}")
        standard_route_flows=master_obj.routeflows_set.all().order_by("seq")
        if standard_route_flows.exists():
            return master_obj
        else:
            logging.info(f"No standard routing available for master")
        
    logging.info(f"Filter master with alternative method: design={design}, mould={mould}, gold_type=g{gold_type}")
    master_objs=routes.Master.objects.filter(design=design,
                                            mould=mould,
                                            gold_type=gold_type
                                            )
    if master_objs.exists():
        master_obj=master_objs.first()
        logging.info(f"Get master {master_obj} with alternative method: design={design}, mould={mould}, gold_type=g{gold_type}")
        standard_route_flows=master_obj.routeflows_set.all().order_by("seq")
        if standard_route_flows.exists():
            return master_obj
        else:
            logging.info(f"No standard routing available for master")
    logging.info(f"No master exists {fg_article=}, {design=}, {mould=}, {gold_type=}")
    return None



def check_flow_is_ok(detail_obj: workorders.Detail) -> str:
    """中央收发或者PF的时候检测: 工单当前进行中的flow是否全部通过

        detail_obj: 检测的单号
        check_name: 是谁调用的

        通过返回:   None
        不通过返回: message
    """
    message = None
    order_route_detail_objs = order_routing.RouteDetail.objects.filter(
        order_route__workorder=detail_obj, status = 2
    )
    if order_route_detail_objs:
        order_route_detail_obj = order_route_detail_objs.first()
        history = frontend_lib.get_routing_history(order_route_detail_obj)
        now_flow = order_route_detail_obj.flow
        if history:
            now_route = history[-1] # 最新的
            if now_flow.scan_and_record and (not(now_route["workerName"] or now_route["startDate"])):
                message = "Qc检验不合格或工单未完成"
            elif now_flow.qc_check and (not now_route["qc_endDate"]):
                message = "Qc校验未通过"
            elif now_flow.stone_exam and (not(now_route["stoneCheck_endDate"])):
                message = "验石员校验未通过"
            elif now_flow.qc_check and now_route["qc_endDate"] and now_flow.leader_check: 
                # qc通过, 组长存在则放行
                return None
            elif now_flow.leader_check and (not(now_route["leader_endDate"])): 
                message = "组长检验未通过"
            return message
    else:
        message = "工序未开始"
        return message